package org.example.controller;

import com.sun.org.apache.xpath.internal.operations.Mod;
import org.example.annotation.LoginCheck;
import org.example.domain.Comment;
import org.example.domain.User;
import org.example.service.imp.*;
import org.example.util.CommonParam;
import org.example.util.CookieUtil;
import org.example.util.HutoolUtil;
import org.example.util.UserThreadLocalUtil;
import org.example.vo.IndexPageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.util.*;

@Controller
@RequestMapping("/user/")
public class UserController {
    @Autowired
    private UserServiceImp userServiceImp;
    @Autowired
    private DiscussServiceImp discussServiceImp;
    @Autowired
    private CommentServiceImp commentServiceImp;
    @Autowired
    private CookieUtil cookieUtil;
    @Autowired
    private LikeServiceImp likeServiceImp;
    @Autowired
    private FollowServiceImp followServiceImp;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private UserThreadLocalUtil userThreadLocalUtil;
    /**
     * 额这个注册功能代码有点乱 算了就不改了 我怕我要起飞
     * 这个注册方法先放一下  都做完了 应该可以了  就是邮箱的授权码出现问题了
     * @param username
     * @param password
     * @param surePassword
     * @param email
     * @param model
     * @return
     */
    @PostMapping("register")
    public String register(@RequestParam("username") String username,
                           @RequestParam("password") String password,
                           @RequestParam("surePassword") String surePassword,
                           @RequestParam("email") String email
            , Model model){
        if (!password.equals(surePassword)){
            model.addAttribute("username",username);
            model.addAttribute("password",password);
            model.addAttribute("surePassword",surePassword);
            model.addAttribute("email",email);
            model.addAttribute(CommonParam.PASSWORD_ERROR,"两次密码不匹配");
        }
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setEmail(email);
        //信息无误 去一个邮件告知页面 js跳转首页 有误当前注册页面信息提示
        Map<String, String> map = userServiceImp.registerUser(user);
        if (map.containsKey(CommonParam.VERIFY_FINISH)) return "site/operate-result";//注册成功  前往跳转页
        else{
            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()){
                String next = iterator.next();
                model.addAttribute(next,map.get(next));
            }
            model.addAttribute("username",username);
            model.addAttribute("password",password);
            model.addAttribute("surePassword",surePassword);
            model.addAttribute("email",email);
            return "site/register";//失败  注册也显示失败信息ve
        }
    }
    @Value("${server.servlet.context-path}")
    private String communityPath ;
    @GetMapping("activation")
    public String activation(Integer id,String activationCode){
        if (id==null || id<=0) return "redirect:/index.html";
        if (activationCode==null || activationCode.equals("") || activationCode.equals(" ") || activationCode.length()<32) return "redirect:/index.html";
        //判断当前id存在与否 activationCode是否正确
        String message = userServiceImp.activationUser(id, activationCode);
        if (message.equals("激活成功")){

            return "redirect:login.html";
        }else {
            return "redirect:/index.html";
        }
    }

    @RequestMapping("login.html")
    public String loginPage(@CookieValue(value = CommonParam.TICKET_SYMBOL,required = false)String ticket ,Model model,HttpServletResponse response){
        if (ticket!=null) {
            //能走到这里 有两种可能 登录了 cookie存在ticket 存在user信息
            //登录了 存在ticket 但是ticket过期(没有自动退出) 不存在user信息  这个就有问题  需要清除数据库中ticket  然后
            IndexPageVO indexPageVO = discussServiceImp.dynamicSearchByUserId(null, CommonParam.DEFAULT_PAGE, CommonParam.DEFAULT_LIMIT);
            model.addAttribute("result",indexPageVO);
            return "/index";
        }
        model.addAttribute("path",communityPath);
        return "site/login";
    }

    @Autowired
    private HutoolUtil hutoolUtil;
    @PostMapping("login")
    public String login(String username,
                        String password,
                        String verifyCode,
                        boolean rememberMe,
                        Model model,
                        @CookieValue(value=CommonParam.TICKET_SYMBOL,required = false) String ticket,
                        HttpSession httpSession,
                        HttpServletResponse response){
        if (ticket!=null){
            return "index";
        }else {
            String code = (String)httpSession.getAttribute(CommonParam.VERIFY_CODE_SYMBOL);
            if (hutoolUtil.stringIsEmpty(verifyCode) || !code.equalsIgnoreCase(verifyCode)){
                //验证码不正确 返回登录页
                model.addAttribute(CommonParam.VERIFY_CODE_ERROR,"验证码不正确");
                model.addAttribute("username",username);
                model.addAttribute("password",password);
                model.addAttribute("verifyCode",verifyCode);
                model.addAttribute("path",communityPath);
                //携带填写的信息
                return "site/login";
            }
            Map<String, String> loginInfo = userServiceImp.login(username, password,rememberMe);
            if (loginInfo.containsKey(CommonParam.VERIFY_FINISH)){
                //登录成功  将一个登录凭证存储到cookie中 然后下次的发送login.html 和 login请求就直接过去 （老这里是所有请求都行）
                //获取cookie存储一个key value
                String tempTicket = loginInfo.get(CommonParam.TICKET_SYMBOL);
                Cookie cookie = new Cookie(CommonParam.TICKET_SYMBOL,tempTicket);
                //设置访问那些资源才携带当前cookie  和  cookie的存活时间
                cookie.setPath(communityPath+"/");
                long cookieAge = System.currentTimeMillis()+(rememberMe?CommonParam.REMEMBER_EXPIRED_TIME:CommonParam.NORMAL_EXPIRED_TIME);
                if (rememberMe) cookie.setMaxAge((int) cookieAge/1000);
                else cookie.setMaxAge((int) cookieAge/1000);
                response.addCookie(cookie);
                User user = userServiceImp.searchByUsername(username);
                userThreadLocalUtil.set(user);
                //登录成功 security存储context
                //用了security 需要将用户存储SecurityContextHolder
                SecurityContext context = SecurityContextHolder.getContext();
                //因为用的是账号密码登录用特定的token

                Authentication authentication = new UsernamePasswordAuthenticationToken(user,user.getPassword(),user.getAuthorities());
                context.setAuthentication(authentication);
                return "redirect:/index.html";
            }else {
                Iterator<String> iterator = loginInfo.keySet().iterator();
                while (iterator.hasNext()){
                    String next = iterator.next();
                    model.addAttribute(next,loginInfo.get(next));
                }
                model.addAttribute("username",username);
                model.addAttribute("password",password);
                model.addAttribute("verifyCode",verifyCode);
                model.addAttribute("path",communityPath);
                return "site/login";
            }
        }

    }
    @LoginCheck
    @GetMapping("setting.html")
    public String setting(@CookieValue(value = CommonParam.TICKET_SYMBOL,required = false) String ticket){
//        User user = userThreadLocalUtil.get();
//        if (user == null || hutoolUtil.stringIsEmpty(ticket)){
//            return "redirect:/index.html";
//        }
        return "site/setting";
    }
    @Autowired
    private TicketServiceImp ticketServiceImp;
    @GetMapping("logout")
    public String logout(@CookieValue(value = CommonParam.TICKET_SYMBOL,required = false) String ticket, HttpServletResponse response){
        cookieUtil.deleteTicket(ticket,response);
        userThreadLocalUtil.remove();
        SecurityContextHolder.clearContext();
        return "redirect:/index.html";
    }


    @PostMapping("headerImgUpload")
    public String headerImgUpload(MultipartFile headerImg, Model model){
        if (headerImg==null){
            model.addAttribute(CommonParam.HEADER_IMG_UPLOAD_ERROR,"文件不存在,上传失败");
            return "site/setting";
        }
        //头像包括的格式 jpg png gif
        String originalFilename = headerImg.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
        if (suffix.contains("jpg") || suffix.contains("png") || suffix.contains("gif")){
            //包含其中一个  将上传的图片保存到工程中
            String classPath = CommonParam.CLASS_PATH;
            String userHeaderFile = classPath+"/static/userHeader";
            File file = new File(userHeaderFile);
            if (!file.exists()){
                file.mkdir();
            }else {
                String randomName = hutoolUtil.randomString(6);
                String newHeaderFileName =  randomName + originalFilename.substring(originalFilename.lastIndexOf('.'));
                File newHeaderFile = new File(userHeaderFile+"/"+newHeaderFileName);
                FileOutputStream fileOutputStream = null;
                BufferedOutputStream bufferedOutputStream = null;
                try {
                    fileOutputStream = new FileOutputStream(newHeaderFile);
                    bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                    bufferedOutputStream.write(headerImg.getBytes());

                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if (fileOutputStream!=null){
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (bufferedOutputStream!=null){
                        try {
                            bufferedOutputStream.close();
                        }catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                User user = userThreadLocalUtil.get();
                //更新数据库中user的headerUrl
                String tempHeaderUrl = "/userHeader/"+newHeaderFileName;
                userServiceImp.updateHeaderUrlById(user.getId(),tempHeaderUrl);
                //更改缓存
                user.setHeaderUrl(tempHeaderUrl);
            }

            model.addAttribute(CommonParam.VERIFY_FINISH,"头像上传成功");
            return "site/setting";
        }else {
            //不包含
            model.addAttribute(CommonParam.HEADER_IMG_UPLOAD_ERROR,"文件不正确,上传失败");
            return "site/setting";
        }
    }
    @PostMapping("updatePassword")
    public String updatePassword(String originPassword,String newPassword,String surePassword,Model model,@CookieValue(value = CommonParam.TICKET_SYMBOL,required = false) String ticket,HttpServletResponse response){
        User user = userThreadLocalUtil.get();

        if (user==null || hutoolUtil.stringIsEmpty(ticket)){
            model.addAttribute("path",communityPath);
            return "site/login";
        }
        if (hutoolUtil.stringIsEmpty(originPassword)){
            model.addAttribute("originPassword","原密码不能为空");
            return "site/setting";
        }
        if (hutoolUtil.stringIsEmpty(newPassword)){
            model.addAttribute("newPassword","新密码不能为空");
            return "site/setting";
        }
        if (hutoolUtil.stringIsEmpty(surePassword)){
            model.addAttribute("surePassword","确认密码不能为空");
            return "site/setting";
        }
        String salt = user.getSalt();
        String md5 = hutoolUtil.md5EncryptHex(originPassword, salt);
        if (!md5.equals(user.getPassword())){
            model.addAttribute("originPassword","原密码不匹配");
            return "site/setting";
        }
        if (!newPassword.equals(surePassword)){
            model.addAttribute("newPassword","新密码不匹配");
            return "site/setting";
        }
        int i = userServiceImp.updatePasswordById(user.getId(),hutoolUtil.md5EncryptHex(newPassword,salt));
        //清除登录凭证
        cookieUtil.deleteTicket(ticket,response);
        return "redirect:/user/login.html";
    }
    @LoginCheck
    @GetMapping("userPage.html")
    public String userPage(@RequestParam(value = "userId",required = false) Integer userId, Model model){
        //获取当前用户的点赞(包括帖子 和 评论)
        //两种方式
        // 第一种 每次访问这个页面都先从数据库获取当前用户发布的帖子 和 评论 id  然后redis数据库查询
        // 第二种 第一次访问查询id 存储redis  每次点赞redis判定是否是当前用的发布的  是 点赞+1 (选择这个) 如果发布新的 需要redis在添加一个
        int currPageUserId = 0;
        if (userId!=null && userId>0){
            //其他用户的详情页
            currPageUserId = userId;
            model.addAttribute("currUser",userServiceImp.searchById(currPageUserId));
        }else {
            //自己的详情页
            currPageUserId = userThreadLocalUtil.get().getId();
            model.addAttribute("currUser",userThreadLocalUtil.get());
        }
        boolean self = false;
        if (userThreadLocalUtil.get().getId() == currPageUserId){
            self = true;
        }
        model.addAttribute("self",self);
        int currUserLikeCount = 0;
        String userKey = CommonParam.USER_PUBLISH_STATUS+currPageUserId;
        Boolean aBoolean = redisTemplate.hasKey(userKey);
        if (aBoolean){
            //存在   获取帖子和评论的id
            currUserLikeCount = likeServiceImp.statistics(currPageUserId);
        }else {
            //不存在  需要从数据库获取当前用户发布的帖子和评论的id
            Map<String,Set<Integer>> paramSet = new HashMap<>();
            List<Integer> discussIds = discussServiceImp.searchUserDiscussIds(currPageUserId);
            if (discussIds!=null && discussIds.size()>0){
                Set<Integer> set = new HashSet<>(discussIds);
                paramSet.put(CommonParam.USER_PUBLISH_DISCUSS_SYMBOL,set);
            }
            List<Integer> commentIds = commentServiceImp.searchUserPublishCommentIds(currPageUserId);
            if (commentIds!=null && commentIds.size()>0){
                Set<Integer> set = new HashSet<>(commentIds);
                paramSet.put(CommonParam.USER_PUBLISH_COMMENT_SYMBOL,set);
            }
            //存储redis
            redisTemplate.opsForHash().putAll(userKey,paramSet);
            //获取点赞
            currUserLikeCount = likeServiceImp.statistics(currPageUserId);
        }
        model.addAttribute("currUserLikeCount",currUserLikeCount);
        //获取关注 和 粉丝数量
        int userFollowCount = followServiceImp.getUserFollowCount(currPageUserId, 3);
        model.addAttribute("followCount",userFollowCount);
        int userFansCount = followServiceImp.getUserFansCount(currPageUserId, 3);
        model.addAttribute("fansCount",userFansCount);
        //如果点击查看自己的详情页就不展示 关注  如果不是 需要判断是否已经关注
        if (currPageUserId !=  userThreadLocalUtil.get().getId()){
            //访问的用户页不是自己需要判断是否是关注过的  一定是别人的主页
            boolean follow = followServiceImp.isFollow(userThreadLocalUtil.get().getId(), 3, currPageUserId);
            model.addAttribute("followStatus",follow);
        }

        return "site/profile";
    }

}
